#include "wnjni.h"

jobject Java_edu_princeton_cogsci_wn_ascii_CIndex_lookup
( JNIEnv* env, jclass ic, jstring jword, jint pos )
{
  jclass illegalArgumentExceptionClass =
    env->FindClass( "java/lang/IllegalArgumentException" );
  jclass wordNetExceptionClass = env->FindClass( WORD_NET_EXCEPTION_CLASS );

  if ( !jword )
  {
    env->ThrowNew( illegalArgumentExceptionClass, "String word was null!" );
    return NULL;
  }
  if ( pos < NOUN || pos > SATELLITE )
  {
    char buf[255];
    sprintf( buf, "int pos=%d was out of range!", pos );
    env->ThrowNew(
      illegalArgumentExceptionClass, buf
    );
    return NULL;
  }

  char* word = strdup( env->GetStringUTFChars( jword, NULL ) );
  if ( !word )
  {
    env->ThrowNew( wordNetExceptionClass, "strdup( ) failed!" );
    return NULL;
  }

  if ( wninit( ) ) {
    env->ThrowNew( wordNetExceptionClass, "wninit( ) failed!" );
    return NULL;
  }

  if ( pos == SATELLITE )
    pos = ADJ;

  IndexPtr is = getindex( word, pos );
  if ( ! is ) {
    return NULL;
  }

  return convert_index( env, ic, is );
}

jobject Java_edu_princeton_cogsci_wn_ascii_CIndex_lookupByOffset
( JNIEnv* env, jclass ic, jint pos, jint offset )
{
  jclass illegalArgumentExceptionClass =
    env->FindClass( "java/lang/IllegalArgumentException" );
  jclass wordNetExceptionClass = env->FindClass( WORD_NET_EXCEPTION_CLASS );

  if ( wninit( ) )
  {
    env->ThrowNew( wordNetExceptionClass, "wninit( ) failed!" );
    return NULL;
  }

  if ( pos == SATELLITE )
    pos = ADJ;

  if ( pos < NOUN || pos > ADV )
  {
    env->ThrowNew( illegalArgumentExceptionClass, "pos out of range!" );
    return NULL;
  }

  IndexPtr is = parse_index( ( long )offset, pos, NULL );

  if ( !is )
    return NULL;

  return convert_index( env, ic, is );
}

jobject convert_index( JNIEnv* env, jclass ic, IndexPtr is )
{
  // is (index struct) is a pointer to the C struct.
  // ic (index class) is the class ID of the class CIndex.
  // io (index object) is an instance of the class CIndex.

  jobject io = env->AllocObject( ic );
  if ( !io )
    return NULL;

  // Set String field.

  env->SetObjectField(
    io,
    env->GetFieldID( ic, "wd", "Ljava/lang/String;" ),
    env->NewStringUTF( is->wd )
  );

  // Set int fields.

  env->SetIntField(
    io, env->GetFieldID( ic, "pos", "I" ), getpos( is->pos )
  );
  env->SetIntField(
    io, env->GetFieldID( ic, "sense_cnt", "I" ), is->sense_cnt
  );
  env->SetIntField(
    io, env->GetFieldID( ic, "off_cnt", "I" ), is->off_cnt
  );
  env->SetIntField(
    io, env->GetFieldID( ic, "tagged_cnt", "I" ), is->tagged_cnt
  );
  env->SetIntField(
    io, env->GetFieldID( ic, "ptruse_cnt", "I" ), is->ptruse_cnt
  );
  env->SetIntField(
    io, env->GetFieldID( ic, "idxoffset", "I" ), ( int )is->idxoffset
  );


  // Set int array fields.

  env->SetObjectField(
    io,
    env->GetFieldID( ic, "ptruse", "[I" ),
    new_ia( env, is->ptruse_cnt, is->ptruse )
  );

  int* offset = new int[ is->off_cnt ];
  for ( int i = 0; i < is->off_cnt; i++ )
    offset[i] = ( int )is->offset[i];
  env->SetObjectField(
    io,
    env->GetFieldID( ic, "offset", "[I" ),
    new_ia( env, is->off_cnt, offset ) );
  delete[] offset;

  return io;
}

